package se.webbzon.boltzmann.editor.list;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;

import javax.swing.AbstractListModel;

public class SortedListModel<T> extends AbstractListModel<T> implements Iterable<T> {
	
	// Auto generated serial version UID
	private static final long serialVersionUID = 5414478088273905186L;

	// The class used in the sorted list
	private final Class<T> clazz;
	
	// The list model
	private final TreeSet<T> model;
	
	/*============================================================
	Constructors
	============================================================*/
	
	/** Created a new sorted list model. **/
	public SortedListModel(Class<T> clazz) {
		this(clazz,(Collection<T>) null);
	}
	
	/** Created a new sorted list model with a given content. **/
	public SortedListModel(Class<T> clazz, Collection<T> collection) {
		this.clazz = clazz;
		model = new TreeSet<T>();
		
		if (collection != null)
			model.addAll(collection);
	}
	
	/** Created a new sorted list model. **/
	public SortedListModel(Class<T> clazz, Comparator<T> comparator) {
		this(clazz,comparator,null);
	}
	
	/** Created a new sorted list model with a given content. **/
	public SortedListModel(	Class<T> clazz, Comparator<T> comparator, 
							Collection<T> collection) {
		this.clazz = clazz;
		model = new TreeSet<T>(comparator);
		
		if (collection != null)
			model.addAll(collection);
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Adds a new element to the sorted list model. **/
	public boolean addElement(T element) {
		if (model.add(element)) {
			fireContentsChanged(this,0,getSize()-1);
			return true;
		} else
			return false;
	}
	
	/** Adds a collection of new elements to the sorted list model. **/
	public boolean addAllElements(Collection<? extends T> elements) {
		if (model.addAll(elements)) {
			fireContentsChanged(this,0,getSize()-1);
			return true;
		} else
			return false;
	}
	
	/** Clears the content of the sorted list model. **/
	public void clearElements() {
		model.clear();
		fireContentsChanged(this,0,getSize()-1);
	}
	
	/** Returns true if the given element was found in the sorted list model. **/
	public boolean containsElement(T element) {
		return model.contains(element);
	}
	
	/** Returns the first element in the sorted list model. **/
	public T firstElement() {
		return model.first();
	}
	
	/** Returns the last element in the sorted list model. **/
	public T lastElement() {
		return model.last();
	}
	
	/** Returns an iterator for the sorted list model. **/
	public Iterator<T> iterator() {
		return model.iterator();
	}
	
	@SuppressWarnings("unchecked")
	@Override public T getElementAt(int index) {
		return model.toArray((T[]) Array.newInstance(clazz, 0))[index];
	}

	@Override public int getSize() {
		return model.size();
	}
	
	/** Removes the element in the sorted list model with the given index. **/
	public void removeElement(int index) {
		Iterator<T> it = iterator();
		for (int i = 0; i < index; i++)
			it.next();
		it.remove();
		fireContentsChanged(this,index,getSize()-1);
	}
	
	/** Removes the given element from the sorted list model. **/
	public void removeElement(T element) {
		model.remove(element);
		fireContentsChanged(this,0,getSize()-1);
	}
	
	/** Resorts all the elements in the sorted list model. **/
	public void resortElements() {
		final HashSet<T> tempSet = new HashSet<T>();
		tempSet.addAll(model);
		model.clear();
		model.addAll(tempSet);
		fireContentsChanged(this,0,getSize()-1);
	}

}
